#ifndef STX_BASE_HPP
#define STX_BASE_HPP

#include <stx/config.hpp>
#include <stx/core/common.hpp>
#include <stx/core/bind.hpp>
#include <stx/core/noncopyable.hpp>
#include <stx/core/type_traits.hpp>
#include <stx/core/binary_constants.hpp>
#include <stx/core/implicit_cast.hpp>
#include <stx/core/bit_cast.hpp>
#include <stx/core/string_conversions.hpp>
#include <stx/core/system_error.hpp>
#include <stx/core/reset.hpp>
#include <stx/core/primitive_types.hpp>
#include <stx/core/get_pointer.hpp>
#include <stx/core/endianness.hpp>
#include <stx/core/default_delete.hpp>
#include <stx/core/null_stream.hpp>
#include <stx/algorithm.hpp>

#define DECLARE_COMMON_TYPE_TYPEDEFS(T) \
    typedef T value_type; \
    typedef T* pointer; \
    typedef const T* const_pointer; \
    typedef T& reference; \
    typedef const T& const_reference;

#define STX_CSTR_(x) #x

#define STX_CSTR(x) STX_CSTR_(x)

#define STX_FILE_LINE_CSTR "file: " __FILE__ "; line: " STX_CSTR(__LINE__)

#ifndef __GNUC__
#define STX_FUNCTION "<unknown>"
#else
#define STX_FUNCTION __FUNCTION__
#endif

#include <cstring> // std::strerror()
#include <stdexcept>
#include <sstream>
#include <typeinfo>

#define STX_THROW(exception_type, message) \
{ \
    std::ostringstream ss__; \
    ss__ << message << " (" STX_FILE_LINE_CSTR "; function: " << STX_FUNCTION << ")"; \
    throw exception_type(ss__.str()); \
}

#define STX_THROW_RUNTIME_ERROR(message) STX_THROW(std::runtime_error, message)

#define STX_THROW_SYSTEM_ERROR_VAL(value, message) \
{ \
    std::ostringstream ss__; \
    ss__ << message << " (" STX_FILE_LINE_CSTR "; function: " << STX_FUNCTION << ")" \
        << "; error message: " << std::strerror(value) << " (errno: " << value << ")"; \
    throw stx::system_error(ss__.str(), value); \
}

#define STX_DESTRUCTOR_SYSTEM_ERROR_VAL(value, message) \
{ \
    std::ostringstream ss__; \
    ss__ << message << " (" STX_FILE_LINE_CSTR "; function: " << STX_FUNCTION << ")" \
        << "; error message: " << std::strerror(value) << " (errno: " << value << ")" \
        << std::endl; \
    std::cerr << ss__.str(); \
}

#define STX_THROW_SYSTEM_ERROR(message) STX_THROW_SYSTEM_ERROR_VAL(errno, message)

#endif // STX_BASE_HPP
